/*****************************************************************************
	File Name:			GameMap.cpp
	Authors:			Marc Willis, Trey Turley, Thomas Lee
	Description:		Contains definitions for the GameMap and GMException
						classes
	Date Modified:		08/07/2010
						- added pointer to external Plotter class with relevant
						  functionality
						08/01/2010
						- made small tweaks
						07/29/2010
						- file created
*****************************************************************************/

#include "GameMap.h"
#include "Draw.h"
#include <iostream>


using namespace std;

/*****************************************************************************
	Function Name:		GameMap()
	Description:		Default constructor for the GameMap class, creates an
						empty GameMap of size x=400, y=300
	Input:
	(none)
	Output:
	(none)
*****************************************************************************/
GameMap::GameMap()
{
	xSize=400;
	ySize=300;
	map=new int*[xSize];
	for(int i=0;i<xSize;i++)
	{
		map[i]=new int[ySize];
		for(int j=0;j<ySize;j++)
		{
			map[i][j]=0;
		}
	}
	playerData[0][0]=1;
	playerData[0][1]=1;
	playerData[0][2]=3;
	playerData[1][0]=xSize-2;
	playerData[1][1]=ySize-2;
	playerData[1][2]=1;
	playerData[2][0]=1;
	playerData[2][1]=ySize-2;
	playerData[2][2]=3;
	playerData[3][0]=xSize-2;
	playerData[3][1]=1;
	playerData[3][2]=4;
}

/*****************************************************************************
	Function Name:		GameMap(int,int, Plotter&)
	Description:		Constructor for the GameMap class, creates an empty
						GameMap of the given size
	Input:
		int x			the xSize of the GameMap
		int y			the ySize of the GameMap
		Plotter &pl		the plotter to be pointed to
	Output:
		(none)
*****************************************************************************/
GameMap::GameMap(int x, int y, Plotter &pl)
{
	xSize=x;
	ySize=y;
	map=new int*[xSize];
	for(int i=0;i<xSize;i++)
	{
		map[i]=new int[ySize];
		for(int j=0;j<ySize;j++)
		{
			if(i==0||j==0||i==xSize-1||j==ySize-1){
				map[i][j]=white;
			}else{
				map[i][j]=0;
			}
		}
	}
	this->p = &pl;
	playerData[0][0]=1;
	playerData[0][1]=1;
	playerData[0][2]=3;
	playerData[1][0]=xSize-2;
	playerData[1][1]=ySize-2;
	playerData[1][2]=1;
	playerData[2][0]=1;
	playerData[2][1]=ySize-2;
	playerData[2][2]=2;
	playerData[3][0]=xSize-2;
	playerData[3][1]=1;
	playerData[3][2]=4;
}

/*****************************************************************************
	Function Name:		GameMap(const GameMap&)
	Description:		Copy constructor for the GameMap class, creates a
						GameMap that matches the one given as a parameter
	Input:
		GameMap &o		the GameMap to be copied
	Output:
		(none)
*****************************************************************************/
GameMap::GameMap(const GameMap &o)
{
	xSize=o.xSize;
	ySize=o.ySize;
	map=new int*[xSize];
	for(int i=0;i<xSize;i++)
	{
		map[i]=new int[ySize];
		for(int j=0;j<ySize;j++)
		{
			map[i][j]=o.map[i][j];
		}
	}
	p=o.p;
	for(int i=0;i<4;i++)
	{
		for(int j=0;j<3;j++)
		{
			playerData[i][j]=o.playerData[i][j];
		}
	}
}

/*****************************************************************************
	Function Name:		GameMap(const istream&,Plotter&)
	Description:		Constructor for the GameMap class, takes information
						from the istream to create a GameMap.  If the data
						ends up being invalid, it creates a GameMap that is
						80x40 and has only the exterior wall.
	Input:
		istream &in		the input file stream to get the GameMap from
		Plotter &pl		the plotter the GameMap will use
	Output:
		(none)
*****************************************************************************/
GameMap::GameMap( istream &in, Plotter &pl)
{
	p=&pl;
	bool valid=true;
	xSize=80;
	ySize=40;
	map=new int*[xSize];
	for(int i=0;i<xSize;i++)
	{
		map[i]=new int[ySize];
	}
	for(int i=0;i<xSize&&valid;i++)
	{
		for(int j=0;j<ySize&&valid;j++)
		{
			if(!in)
			{
				valid=false;
			}else{
				in>>map[i][j];
			}
		}
	}
	for(int i=0;i<4&&valid;i++)
	{
		for(int j=0;j<3&&valid;j++)
		{
			if(!in)
			{
				valid=false;
			}else{
				in>>playerData[i][j];
			}
		}
	}
	if(!valid)
	{
		for(int i=0;i<xSize;i++)
		{
			map[i]=new int[ySize];
			for(int j=0;j<ySize;j++)
			{
				if(i==0||j==0||i==xSize-1||j==ySize-1){
					map[i][j]=white;
				}else{
					map[i][j]=0;
				}
			}
		}
		playerData[0][0]=1;
		playerData[0][1]=1;
		playerData[0][2]=3;
		playerData[1][0]=xSize-2;
		playerData[1][1]=ySize-2;
		playerData[1][2]=1;
		playerData[2][0]=ySize-2;
		playerData[2][1]=2;
		playerData[2][2]=2;
		playerData[3][0]=xSize-2;
		playerData[3][1]=1;
		playerData[3][2]=4;
	}
}

/*****************************************************************************
	Function Name:		~GameMap()
	Description:		Destructor for the GameMap class, frees dynamically
						allocated memory
	Input:
		(none)
	Output:
		(none)
*****************************************************************************/
GameMap::~GameMap()
{
	for(int i=0;i<xSize;i++)
	{
		delete [] map[i];
		map[i]=NULL;
	}
	delete [] map;
	map=NULL;
}

/*****************************************************************************
	Function Name:		getColor(int, int)
	Description:		returns the color of the given block, 0 for empty
	Input:
		int x			the x of the desired block
		int y			the y of the desired block
	Output:
		int				the color of the desired block
*****************************************************************************/
int GameMap::getColor(int x, int y)
{
	if(x<0){
		throw GMException("x<0 in getColor");
	}
	if(y<0){
		throw GMException("y<0 in getColor");
	}
	if(x>=xSize){
		throw GMException("x outside of boundaries in getColor");
	}
	if(y>=ySize){
		throw GMException("y outside of boundaries in getColor");
	}
	return map[x][y];
}

/*****************************************************************************
	Function Name:		isSafe(int, int)
	Description:		returns true if the given block is a "safe" color (one
						that the player can land on without losing), otherwise
						returns false
	Input:
		int x			the x of the desired block
		int y			the y of the desired block
	Output:
		bool			the "safety" status of the given block
*****************************************************************************/
bool GameMap::isSafe(int x, int y)
{
	if(x<0||x>=xSize||y<0||y>=ySize)
	{
		return false;
	}
	if(!map[x][y])
	{
		return true;
	}
	return false;
}

/*****************************************************************************
	Function Name:		markBlock(int, int, int)
	Description:		"colors" the given block with the given color
	Input:
		int x			the x of the desired block
		int y			the y of the desired block
		int color		the color to make the desired block
		int dir			the direction of the player
	Output:
		(none)
*****************************************************************************/
void GameMap::markBlock(int x, int y, int color, int dir)
{
	if(x<0){
		throw GMException("x<0 in markBlock");
	}
	if(y<0){
		throw GMException("y<0 in markBlock");
	}
	if(x>=xSize){
		throw GMException("x outside of boundaries in markBlock");
	}
	if(y>=ySize){
		throw GMException("y outside of boundaries in markBlock");
	}
	map[x][y]=color;

	//Draw on Map
	p->plotTrail(x,y,color,dir);
}

/*****************************************************************************
	Function Name:		getPD(int, int)
	Description:		Gets info from playerData
	Input:
		int player		the player whose info you want (0-3)
		int value		the value desired (0=x,1=y,2=dir)
	Output:
		int				the value requested
*****************************************************************************/
int GameMap::getPD(int player, int value)
{
	if(player<0||player>3)
	{
		throw GMException("Invalid player number in getPlayerData");
	}
	if(value<0||value>2)
	{
		throw GMException("Invalid value in getPlayerData");
	}
	return playerData[player][value];
}

/*****************************************************************************
	Function Name:		drawMap()
	Description:		draws the current map to the plotter pointed to by p
	Input:
		(none)
	Output:
		(none)
*****************************************************************************/
void GameMap::drawMap()
{
	for(int i=0;i<xSize;i++)
	{
		for(int j=0;j<ySize;j++)
		{
			p->plotTrail(i,j,map[i][j],SQUARE);
		}
	}
}

/*****************************************************************************
	Function Name:		GMException()
	Description:		Default constructor for the GMException class, creates
						an "unknown GMException"
	Input:
		(none)
	Output:
		(none)
*****************************************************************************/
GMException::GMException()
{
	error=new char[8];
	error[0]='U';
	error[1]='n';
	error[2]='k';
	error[3]='n';
	error[4]='o';
	error[5]='w';
	error[6]='n';
	error[7]='\0';
}

/*****************************************************************************
	Function Name:		GMException(const GMException&)
	Description:		Copy constructor for the GMException class, more of a
						failsafe than anything, as I don't think it should be
						called.
	Input:
		GMException &o	the GMException to be copied
	Output:
		(none)
*****************************************************************************/
GMException::GMException(const GMException &o)
{
	int i;
	for(i=0;o.error[i]!='\0';i++);
	error=new char[i+1];
	for(i=0;o.error[i]!='\0';i++)
	{
		error[i]=o.error[i];
	}
	error[i]='\0';
}

/*****************************************************************************
	Function Name:		GMException(const char*)
	Description:		Constructor for the GMException class, creates an 
						exception that prints the reason given in the string
	Input:
		char* str		the error message
	Output:
		(none)
*****************************************************************************/
GMException::GMException(char *str)
{
	int i;
	for(i=0;str[i]!='\0';i++);
	error=new char[i+1];
	for(i=0;str[i]!='\0';i++)
	{
		error[i]=str[i];
	}
	error[i]='\0';
}

/*****************************************************************************
	Function Name:		~GMException()
	Description:		Destructor for the GMException class, frees
						memory
	Input:
		(none)
	Output:
		(none)
*****************************************************************************/
GMException::~GMException()
{
	delete [] error;
}

/*****************************************************************************
	Function Name:		printEx(ostream&)
	Description:		prints the reason for the exception to the given
						ostream
	Input:
		ostream &out	the ostream to be printed to
	Output:
		(none)
*****************************************************************************/
void GMException::printEx(ostream &out)
{
	out<<"GameMap Exception:"<<error;
}
